package org.dtrd.modules.doctor.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.dtrd.common.util.CheckUtil;
import org.dtrd.common.util.DateUtils;
import org.dtrd.config.system.Constant;
import org.dtrd.config.system.Constant.DoctorConcernPatientStatus;
import org.dtrd.config.system.Constant.DoctorPatientRelationType;
import org.dtrd.config.system.Constant.DoctorQueryPatientType;
import org.dtrd.modules.doctor.entity.bean.*;
import org.dtrd.modules.doctor.entity.po.DtrdEntRdDoctor;
import org.dtrd.modules.doctor.entity.po.DtrdEntRdDoctorConcernPatient;
import org.dtrd.modules.doctor.entity.po.DtrdRlDoctorPatient;
import org.dtrd.modules.doctor.mapper.DtrdRlDoctorPatientMapper;
import org.dtrd.modules.doctor.service.*;
import org.dtrd.modules.patient.entity.bean.PatientH5ListInfo;
import org.dtrd.modules.patient.entity.po.DtrdEntRdPatient;
import org.dtrd.modules.patient.service.IDtrdEntRdPatientService;
import org.dtrd.modules.record.entity.po.DtrdEntRdSigninSugarValue;
import org.dtrd.modules.record.service.ISugarRecordService;
import org.dtrd.modules.service.entity.po.DtrdRlPackagePatient;
import org.dtrd.modules.service.service.IDtrdRlPackagePatientService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.stream.Collectors;

import static org.dtrd.config.system.Constant.Group.NO_GROUP;


/**
 * <p>
 * 医生-患者 服务实现类
 * </p>
 *
 * @author QR
 * @since 2021-12-17
 */
@DS("multi-datasource1")
@Service
@Slf4j
public class DtrdRlDoctorPatientServiceImpl extends ServiceImpl<DtrdRlDoctorPatientMapper, DtrdRlDoctorPatient> implements IDtrdRlDoctorPatientService {

    @Autowired
    private IDtrdEntRdPatientService patientService;
    @Autowired
    private IDtrdEntRdDoctorService doctorService;
    @Autowired
    private IDtrdEntRdDoctorConcernPatientService doctorConcernPatientService;
    @Autowired
    private IDtrdRlPackagePatientService packagePatientService;
    @Autowired
    private ISugarRecordService sugarValueService;


    @Override
    public List<DoctorPatientListInfo> getDoctorPatientList(DoctorPatientListRequest request) {
        LambdaQueryWrapper<DtrdRlDoctorPatient> queryWrapper = baseQueryWrapper();
        List<DtrdRlDoctorPatient> poList = list(queryWrapper);
        List<DoctorPatientListInfo> dtoList = new ArrayList<>(poList.size());
        if (!poList.isEmpty()) {
            dtoList = poList.stream().map(DoctorPatientListInfo::new).collect(Collectors.toList());
        }
        return dtoList;
    }

    @Override
    public IPage<DoctorPatientListInfo> pageDoctorPatient(DoctorPatientPageRequest request) {
        LambdaQueryWrapper<DtrdRlDoctorPatient> queryWrapper = baseQueryWrapper();
        IPage<DtrdRlDoctorPatient> page = new Page<>(request.getPageNum(), request.getPageSize());
        page = this.page(page, queryWrapper);
        return page.convert(DoctorPatientListInfo::new);
    }

    @Override
    public List<Integer> listPatientIdsByDoctorId(Integer doctorId) {
        LambdaQueryWrapper<DtrdRlDoctorPatient> wrapper = baseQueryWrapper().eq(DtrdRlDoctorPatient::getDoctorId, doctorId);
        List<DtrdRlDoctorPatient> doctorPatients = list(wrapper);
        if (CollectionUtil.isNotEmpty(doctorPatients)) {
            return doctorPatients.stream().map(DtrdRlDoctorPatient::getPatientId).collect(Collectors.toList());
        }
        return null;
    }

    @Override
    public List<Integer> listPatientIdsByDoctorId(List<Integer> doctorIdList) {
        return baseMapper.listPatientIdsByDoctorId(doctorIdList);
    }

    @Override
    public Integer getDoctorIdByPatientId(Integer patientId) {
        DtrdRlDoctorPatient doctorPatient = getRecordByPatientId(patientId);
        log.info("DtrdRlDoctorPatientServiceImpl.getDoctorIdByPatientId.[patientId  = " + patientId + "; doctorPatient= " + doctorPatient);
        return Optional.ofNullable(doctorPatient).map(DtrdRlDoctorPatient::getDoctorId).orElse(null);
    }

    private DtrdRlDoctorPatient getRecordByPatientId(Integer patientId) {
        LambdaQueryWrapper<DtrdRlDoctorPatient> wrapper = baseQueryWrapper().eq(DtrdRlDoctorPatient::getPatientId, patientId).orderByDesc(DtrdRlDoctorPatient::getCreateTime).last("limit 1");
        return getOne(wrapper);
    }

    @Override
    public DoctorPatientDetail getDoctorPatient(Integer dataId) {
        DtrdRlDoctorPatient dtrdRlDoctorPatient = getById(dataId);
        return Optional.ofNullable(dtrdRlDoctorPatient).map(po -> new DoctorPatientDetail().parseFromPo(po)).orElse(null);
    }

    @Override
    public boolean saveOrUpdateDoctorPatient(DoctorPatientDetail dto) {
        DtrdRlDoctorPatient dtrdRlDoctorPatient = new DtrdRlDoctorPatient();
        if (dto.getDataId() == null) {
            dtrdRlDoctorPatient = dtrdRlDoctorPatient.init();
        }
        dtrdRlDoctorPatient.parseFromDto(dto);
        return saveOrUpdate(dtrdRlDoctorPatient);
    }

    @Override
    public boolean removeDoctorPatient(Integer dataId) {
        return removeById(dataId);
    }

    @Override
    public Integer countDoctorGroupPatient(Integer doctorId, Integer groupId) {
        return count(Wrappers.lambdaQuery(DtrdRlDoctorPatient.class).eq(DtrdRlDoctorPatient::getDoctorId, doctorId).eq(DtrdRlDoctorPatient::getGroupId, groupId));
    }

    @Override
    public boolean saveOrUpdateDoctorPatientRelation(Integer doctorId, Integer patientId, int relationType) {
//        LambdaQueryWrapper<DtrdRlDoctorPatient> wrapper = Wrappers.lambdaQuery(DtrdRlDoctorPatient.class)
//                .eq(DtrdRlDoctorPatient::getPatientId, patientId)
//                .eq(DtrdRlDoctorPatient::getDoctorId, doctorId);
//        DtrdRlDoctorPatient doctorPatient = new DtrdRlDoctorPatient(patientId, doctorId);
//        saveOrUpdate(doctorPatient, wrapper);
        // 设置 patient 表的 doctorId 字段
        DtrdEntRdPatient queryPatient = patientService.getById(patientId);
        if (queryPatient == null) {
            return false;
        }
        queryPatient.setDoctorId(doctorId);
        boolean result1 = patientService.updateById(queryPatient);
        if (!result1) {
            return false;
        }
        DtrdEntRdDoctor queryDoctor = doctorService.getById(doctorId);
        if (queryDoctor == null) {
            return false;
        }
        Integer doctorIdByPatientId = getDoctorIdByPatientId(patientId);
        boolean result2 = true;
        if (doctorIdByPatientId == null) {
            // doctorPatientRelation, 存 dtrd_rl_doctor_patient 表
            DtrdRlDoctorPatient dpRl = new DtrdRlDoctorPatient().init();
            dpRl.setDoctorId(doctorId);
            dpRl.setPatientId(patientId);
            dpRl.setDoctorType(queryDoctor.getDoctorsType());
            dpRl.setDoctorPatientsRelationType(relationType);
            // 默认为未分组
            dpRl.setGroupId(NO_GROUP.getType());
            dpRl.setChatRoomId(IdWorker.get32UUID());
            result2 = save(dpRl);
        }
        return result1 && result2;
    }

    @Override
    public Map<Integer, Integer> getPatientIdToDoctorIdMap(List<Integer> patientIds) {
        LambdaQueryWrapper<DtrdRlDoctorPatient> wrapper = baseQueryWrapper().in(DtrdRlDoctorPatient::getPatientId, patientIds).orderByAsc(DtrdRlDoctorPatient::getCreateTime);
        List<DtrdRlDoctorPatient> doctorPatients = list(wrapper);
        if (CollectionUtil.isNotEmpty(doctorPatients)) {
            HashMap<Integer, Integer> map = new HashMap<>(doctorPatients.size());
            doctorPatients.forEach(dp -> {
                map.put(dp.getPatientId(), dp.getDoctorId());
            });
            return map;
        }
        return null;
    }

    @Override
    public List<PatientServiceInfo> getPatientInfomationInDoctorService(List<Integer> doctorIdList, Integer packageId) {
        return baseMapper.getPatientInfomationInDoctorService(doctorIdList, packageId);
    }

    @Override
    public String getChatroomIdByPatientId(Integer patientId, Integer doctorId) {
        DtrdRlDoctorPatient po = baseMapper.getDpRlByPatientId(patientId, doctorId);
        if (po == null) {
            return null;
        } else {
            if (po.getChatRoomId() == null) {
                po.setChatRoomId(IdWorker.get32UUID());
                updateById(po);
            }
            return po.getChatRoomId();
        }
    }

    @Override
    public boolean concernPatient(Integer doctorId, Integer patientId, Integer patientsCollected) {
        Integer result = baseMapper.updateConcernState(patientsCollected, patientId, doctorId);
        log.info("DtrdRlDoctorPatientServiceImpl.concernPatient.[doctorId = {}, patientId={}, patientsCollected={},result={}", doctorId, patientId, patientsCollected, result);
        return null != result && result >= 1;
    }

    @Override
    public List<DtrdRlDoctorPatient> getRelativeRecords() {
        return baseMapper.getRelativeRecords();
    }

    @Override
    public void onSugarRecord(Integer patientId, Integer dataId, Date recordDate) {
        DtrdRlDoctorPatient po = getRecordByPatientId(patientId);
        if (po != null) {
            po.setMeasureRecordId(dataId);
            po.setMeasureRecordDate(recordDate);
            updateById(po);
        }
    }

    @Override
    public int[] getH5Statistics(Integer doctorId) {
        int[] array = new int[3];
        // 今日测量
        List<DoctorStatisticsItem> list = baseMapper.getPatientCount(doctorId, DateUtils.formatDate(), null);
        if (CollectionUtil.isNotEmpty(list)) {
            array[0] = list.get(0).getSummary();
        }
        // 未测量
        List<DoctorStatisticsItem> patientList = baseMapper.getPatientCount(doctorId, null, null);
        if (CollectionUtil.isNotEmpty(patientList)) {
            array[1] = patientList.get(0).getSummary() - array[0];
        }
        // 扫码患者
        List<DoctorStatisticsItem> scanPatientList = baseMapper.getPatientCount(doctorId, null, DoctorPatientRelationType.getScanType());
        if (CollectionUtil.isNotEmpty(scanPatientList)) {
            array[2] = scanPatientList.get(0).getSummary();
        }
        log.info("DtrdRlDoctorPatientServiceImpl.getH5Statistics.[doctorId] array=" + JSON.toJSONString(array));
        return array;
    }

    @Override
    public List<DoctorStatisticsItem> getScanPatientStatistics(Integer doctorId, String orgCode) {
        return baseMapper.getPatientCount(doctorId, null, DoctorPatientRelationType.getScanType());
    }

    @Override
    public List<DoctorStatisticsItem> getScanPatientStatisticsV2(List<Integer> teamDoctorIdList) {
        return baseMapper.getPatientCountV2(teamDoctorIdList, null, DoctorPatientRelationType.getScanType());
    }

    @Override
    public List<DoctorStatisticsItem> getPatientStatisticsV2(List<Integer> teamDoctorIdList) {
        return baseMapper.getPatientCountV2(teamDoctorIdList, null, DoctorPatientRelationType.getScanType());
    }

    /**
     * 统计医生所有患者
     *
     * @param doctorId
     * @param orgCode
     * @return
     */
    @Override
    public List<DoctorStatisticsItem> getPatientStatistics(Integer doctorId, String orgCode) {
        return baseMapper.getPatientCount(doctorId, null, null);
    }

    @Override
    public IPage<PatientH5ListInfo> pageConcernPatientList(Integer doctorId, Integer pageNum, Integer pageSize) {
        IPage<PatientH5ListInfo> page = new Page<>(pageNum, pageSize);
        page = baseMapper.pageConcernPatientList(page, doctorId);
        List<PatientH5ListInfo> records = page.getRecords();
        DtrdEntRdDoctor doctor = doctorService.getById(doctorId);
        Map<Integer, String> doctorMap = new HashMap<>(1);
        doctorMap.put(doctorId, doctor.getDoctorsName());
        handlePatientRecords(records, null, true, doctorMap);
        return page;
    }

    @Override
    public IPage<PatientH5ListInfo> pageRelationPatientList(List<Integer> doctorIdList, @NotNull Integer doctorId, Integer type, Integer subType, Integer pageNum, Integer pageSize) {
        IPage<PatientH5ListInfo> page = new Page<>(pageNum, pageSize);
        String recordDate = null, relationTypes = null;
        if (type == DoctorQueryPatientType.SCAN_PATIENT.getType()) {
            relationTypes = Constant.DoctorPatientRelationType.getScanType();
            page = baseMapper.pageScanRelationPatientList(page, doctorIdList, relationTypes, subType);
        } else {
            recordDate = DateUtils.formatDate();
            page = baseMapper.pageRelationPatientList(page, doctorIdList, recordDate, null, type);
        }
        List<PatientH5ListInfo> records = page.getRecords();
        log.info("DtrdRlDoctorPatientServiceImpl.pageRelationPatientList.[doctorId=" + doctorIdList + ", type=" + type + ", recordDate=" + recordDate + "; relation=" + relationTypes + " \nrecords=" + records);
        if (CheckUtil.isNotEmpty(records)) {
            // 处理是否关注
            Map<Integer, Integer> dcpMap = queryDoctorConcernPatientByDoctorId(doctorId);
            log.info("DtrdRlDoctorPatientServiceImpl.pageRelationPatientList.[doctorIdList, doctorId, type, subType, pageNum, pageSize] map==" + dcpMap);
            // 批量查询医生信息
            List<DtrdEntRdDoctor> doctorList = doctorService.getDoctorByIdList(doctorIdList);
            Map<Integer, String> doctorMap = new HashMap<>(doctorList.size());
            doctorList.stream().forEach(doctor -> {
                doctorMap.put(doctor.getDataId(), doctor.getDoctorsName());
            });
            handlePatientRecords(records, dcpMap, false, doctorMap);
//            log.info("DtrdRlDoctorPatientServiceImpl.pageRelationPatientList.[doctorIdList, doctorId, type, subType, pageNum, pageSize] after handle collect state records" + records);
        }
        return page;
    }

    /**
     * 删除医患关联、删除重点关注
     *
     * @param patientIds
     */
    @Override
    public void deleteRecordByPatientIds(Set<Integer> patientIds) {
        if (CollectionUtil.isNotEmpty(patientIds)) {
            baseMapper.deleteRecordByPatientIds(patientIds);
            doctorConcernPatientService.deleteRecordByPatientIds(patientIds);
        }
    }

    @Override
    public List<DoctorStatisticsItem> countServingPatient(Integer doctorId) {
        return baseMapper.countServingPatient(doctorId);
    }

    @Override
    public List<DoctorStatisticsItem> countServingPatientV2(List<Integer> doctorIdList) {
        return baseMapper.countServingPatientV2(doctorIdList);
    }

    @Override
    public List<DoctorStatisticsItem> countBindDevicePatient(Integer doctorId) {
        return baseMapper.countBindDevicePatient(doctorId);
    }

    @Override
    public List<DoctorStatisticsItem> countBindDevicePatientV2(List<Integer> doctorIdList) {
        return baseMapper.countBindDevicePatientV2(doctorIdList);
    }

    private void handlePatientRecords(List<PatientH5ListInfo> records, Map<Integer, Integer> dcpMap, boolean allConcern, Map<Integer, String> doctorArray) {
        if (CollectionUtil.isNotEmpty(records)) {
            // 循环得到用户ID集合 一次查询避免循环查询
            StringJoiner sj = new StringJoiner(",", "(", ")");
            records.stream().map(item -> item.getPatientId() + "").forEach(sj::add);
            // 服务包开始与结束时间
            Map<Integer, DtrdRlPackagePatient> servicePackageMap = getServicePackageDuration(sj.toString());
            // 最近一条空腹血糖
            Map<Integer, DtrdEntRdSigninSugarValue> sugarValueMap = getLatestFastingSugarValue(sj.toString());
            records.forEach(item -> {
                // 处理年龄
                if (item.getBirthday() != null) {
                    item.setPatientsAge(DateUtil.age(item.getBirthday(), null));
                }
                // 处理医生姓名
                item.setDoctorName(doctorArray.get(item.getDoctorId()));
                // 处理关注状态
                if (allConcern) {
                    item.setPatientsCollected(DoctorConcernPatientStatus.CONCERN.getStatus());
                } else {
                    if (dcpMap != null) {
                        Integer dcpRecord = dcpMap.get(item.getPatientId());
                        item.setPatientsCollected(dcpRecord == null ? DoctorConcernPatientStatus.UNCONCERN.getStatus() : DoctorConcernPatientStatus.CONCERN.getStatus());
                    }
                }
                // 处理服务包时间
                if (servicePackageMap != null) {
                    DtrdRlPackagePatient po = servicePackageMap.get(item.getPatientId());
                    if (po != null) {
                        item.setStartTime(DateUtil.formatDate(po.getStartTime()));
                        item.setEndTime(DateUtil.formatDate(po.getEndTime()));
                    }
                }
                // 处理血糖记录
                if (sugarValueMap != null) {
                    DtrdEntRdSigninSugarValue po = sugarValueMap.get(item.getPatientId());
                    if (po != null) {
                        item.setPatientsRecordTime(DateUtil.formatDateTime(po.getRecordTime()));
                        item.setSugarStatus(po.getSugarValueType());
                        item.setRecordValue(po.getSugarValueSugarValue());
                        item.setRecordName(Optional.ofNullable(Constant.SugarRecordType.valueOf(po.getSugarValueTimeTypeId())).orElse(Constant.SugarRecordType.RANDOMTIME).getName());
                    }
                }
            });
        }
    }

    /**
     * 查询是否关联
     *
     * @param doctorId 如：(1,2,3,4)
     * @return
     */
    private Map<Integer, Integer> queryDoctorConcernPatientByDoctorId(@NotNull Integer doctorId) {
        List<DtrdEntRdDoctorConcernPatient> list = doctorConcernPatientService.getConcernRecords(doctorId);
        if (CollectionUtil.isNotEmpty(list)) {
            Map<Integer, Integer> map = new HashMap<>(list.size());
            list.forEach(po -> map.put(po.getPatientId(), po.getPatientId()));
            return map;
        }
        return null;
    }

    /**
     * 查询患者服务包开始与结束时间
     *
     * @param patientIds
     * @return
     */
    private Map<Integer, DtrdRlPackagePatient> getServicePackageDuration(String patientIds) {
        List<DtrdRlPackagePatient> list = packagePatientService.getServicePackageDuration(patientIds);
        if (CollectionUtil.isNotEmpty(list)) {
            Map<Integer, DtrdRlPackagePatient> map = new HashMap<>(list.size());
            list.forEach(po -> map.put(po.getPatientId(), po));
            return map;
        }
        return null;
    }

    /**
     * 查询患者最近血糖记录
     *
     * @param patientIds
     * @return
     */
    private Map<Integer, DtrdEntRdSigninSugarValue> getLatestFastingSugarValue(String patientIds) {
        List<DtrdEntRdSigninSugarValue> list = sugarValueService.getLatestSugarValue(patientIds, null);
        if (CollectionUtil.isNotEmpty(list)) {
            Map<Integer, DtrdEntRdSigninSugarValue> map = new HashMap<>(list.size());
            list.forEach(po -> {
                if (!map.containsKey(po.getPatientId())) {
                    map.put(po.getPatientId(), po);
                }
            });
            log.info("DtrdRlDoctorPatientServiceImpl.getLatestFastingSugarValue.[patientIds] map=" + map);
            return map;
        }
        return null;
    }

    private LambdaQueryWrapper<DtrdRlDoctorPatient> baseQueryWrapper() {
        return Wrappers.lambdaQuery(DtrdRlDoctorPatient.class).eq(DtrdRlDoctorPatient::getIsDel, 0);
    }

    private LambdaUpdateWrapper<DtrdRlDoctorPatient> baseUpdateWrapper() {
        return Wrappers.lambdaUpdate(DtrdRlDoctorPatient.class).eq(DtrdRlDoctorPatient::getIsDel, 0);
    }
}
